package com.jinlia.show.modules.base.system.service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jinlia.show.common.core.exception.MyRuntimeException;
import com.jinlia.show.modules.base.system.entity.IdGenerator;
import com.jinlia.show.modules.base.system.mapper.IdGeneratorMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Objects;

@Service
@RequiredArgsConstructor
public class IdGeneratorMapperService extends ServiceImpl<IdGeneratorMapper, IdGenerator> {
    DateTimeFormatter yyMMdd = DateTimeFormatter.ofPattern("yyMMdd");

    @Transactional
    public String generateOrderNum() {
        IdGenerator orderNum = this.lambdaQuery().eq(IdGenerator::getIdType, "orderNum").one();
        if (orderNum == null) {
            orderNum = new IdGenerator();
            orderNum.setCurrentId(100l); //第一单显示为A01  故初始id=100
            orderNum.setIdType("orderNum");
            orderNum.setCurrentDay(LocalDate.now());
            orderNum.setCurrentIdStr("S" + LocalDate.now().format(yyMMdd) + convertToBase26(orderNum.getCurrentId()));
            orderNum.setVersion(0);
            this.save(orderNum);//
        }
        long currentId = LocalDate.now().equals(orderNum.getCurrentDay()) ? orderNum.getCurrentId() : 100;
        //下一个
        orderNum.setCurrentId(currentId + 1);
        orderNum.setCurrentIdStr("S" + LocalDate.now().format(yyMMdd) + convertToBase26(orderNum.getCurrentId()));
        boolean update = this.lambdaUpdate()
                .set(IdGenerator::getCurrentDay, LocalDate.now())
                .set(IdGenerator::getCurrentId, orderNum.getCurrentId())
                .set(IdGenerator::getCurrentIdStr, orderNum.getCurrentIdStr())
                .eq(IdGenerator::getId, orderNum.getId())
                .eq(IdGenerator::getVersion, orderNum.getVersion()) //乐观锁
                .update();
        int tryTimes = 0;
        //重试
        while (!update){
            if (tryTimes >3) {
                throw new MyRuntimeException("下单人数爆满,请稍后再试试!!!");
            }
            tryTimes = tryTimes +1;
            orderNum = this.lambdaQuery().eq(IdGenerator::getIdType, "orderNum").one();
            currentId = LocalDate.now().equals(orderNum.getCurrentDay()) ? orderNum.getCurrentId() : 100;
            //下一个
            orderNum.setCurrentId(currentId + 1);
            orderNum.setCurrentIdStr("S" + LocalDate.now().format(yyMMdd) + convertToBase26(orderNum.getCurrentId()));
            update = this.lambdaUpdate()
                    .set(IdGenerator::getCurrentDay, LocalDate.now())
                    .set(IdGenerator::getCurrentId, orderNum.getCurrentId())
                    .set(IdGenerator::getCurrentIdStr, orderNum.getCurrentIdStr())
                    .eq(IdGenerator::getId, orderNum.getId())
                    .eq(IdGenerator::getVersion, orderNum.getVersion()) //乐观锁
                    .update();
        }
        return orderNum.getCurrentIdStr();
    }

    @Transactional
    public String generateDeliveryOrderNum() {
        //数据库锁，阻止其他事务查看
        IdGenerator orderNum = this.lambdaQuery().eq(IdGenerator::getIdType, "deliveryOrderNum").one();
        if (orderNum == null) {
            orderNum = new IdGenerator();
            orderNum.setCurrentId(100l);
            orderNum.setIdType("deliveryOrderNum");
            orderNum.setCurrentDay(LocalDate.now());
            orderNum.setCurrentIdStr("D" + LocalDate.now().format(yyMMdd) + convertToBase26(orderNum.getCurrentId()));
            orderNum.setVersion(0);
            this.save(orderNum);//
        }
        //第一单显示为A01  故初始id=100
        Long currentId = LocalDate.now().equals(orderNum.getCurrentDay()) ? orderNum.getCurrentId() : 100;
        //下一个
        orderNum.setCurrentId(currentId + 1);
        orderNum.setCurrentIdStr("D" + LocalDate.now().format(yyMMdd) + convertToBase26(orderNum.getCurrentId()));
        boolean update = this.lambdaUpdate()
                .set(IdGenerator::getCurrentDay, LocalDate.now())
                .set(IdGenerator::getCurrentId, orderNum.getCurrentId())
                .set(IdGenerator::getCurrentIdStr, orderNum.getCurrentIdStr())
                .eq(IdGenerator::getId, orderNum.getId())
                .eq(IdGenerator::getVersion, orderNum.getVersion()) //乐观锁
                .update();
        int tryTimes = 0;
        //重试
        while (!update){
            if (tryTimes >3) {
                throw new MyRuntimeException("下单人数爆满,请稍后再试试!!!");
            }
            tryTimes = tryTimes +1;
            orderNum = this.lambdaQuery().eq(IdGenerator::getIdType, "deliveryOrderNum").one();
            currentId = LocalDate.now().equals(orderNum.getCurrentDay()) ? orderNum.getCurrentId() : 100;
            //下一个
            orderNum.setCurrentId(currentId + 1);
            orderNum.setCurrentIdStr("D" + LocalDate.now().format(yyMMdd) + convertToBase26(orderNum.getCurrentId()));
            update = this.lambdaUpdate()
                    .set(IdGenerator::getCurrentDay, LocalDate.now())
                    .set(IdGenerator::getCurrentId, orderNum.getCurrentId())
                    .set(IdGenerator::getCurrentIdStr, orderNum.getCurrentIdStr())
                    .eq(IdGenerator::getId, orderNum.getId())
                    .eq(IdGenerator::getVersion, orderNum.getVersion()) //乐观锁
                    .update();
        }
        return orderNum.getCurrentIdStr();
    }

    /**
     * @param decimalNumber
     * @return
     */
    public static String convertToBase26(long decimalNumber) {
        Long num = decimalNumber % 100;//取余
        StringBuilder base25Number = new StringBuilder();
        String alphabet = "0ABCDEFGHIJKLMNPQRSTUVWXYZ";
        decimalNumber = decimalNumber / 100;//取整
        while (decimalNumber > 0) {
            long remainder = decimalNumber % 26;//取余
            base25Number.append(alphabet.charAt((int) remainder));//索引冲0开始
            decimalNumber /= 26;//取整
        }
        base25Number = base25Number.reverse();
        if (num < 10) {
            base25Number.append("0").append(num);
        } else {
            base25Number.append(num);
        }

        return base25Number.toString();
    }

}
